package com.cmc.cloud.cmclink.doc.service.impl.special;

import cn.hutool.core.collection.CollectionUtil;
import com.cmc.cloud.cmclink.doc.api.document.emums.PackingEnum;
import com.cmc.cloud.cmclink.doc.api.document.emums.SpecialEnum;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.SpecialCargoApplyErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.convert.*;
import com.cmc.cloud.cmclink.doc.entity.*;
import com.cmc.cloud.cmclink.doc.mapper.*;
import com.cmc.cloud.cmclink.doc.service.ApplySaveOrUpdateService;
import com.cmc.cloud.cmclink.doc.service.special.SpcExternalApiService;
import com.cmc.cloud.cmclink.doc.util.sepcial.CommonUtil;
import com.cmc.cloud.cmclink.doc.vo.special.externalapivo.*;
import com.cmc.cloud.cmclink.doc.vo.specialcargocasvo.CasCreateOrUpdateVO;
import com.cmc.cloud.cmclink.doc.vo.specialcargocntrvo.SpecialCargoCntrBaseVO;
import com.cmc.cloud.cmclink.doc.vo.specialcargodgpackingvo.PackingCreateOrUpdateVO;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 特种货主信息申请对外接口 Service 实现类
 *
 * @author 集运管理员
 */
@Service
@Validated
public class SpcExternalApiServiceImpl implements SpcExternalApiService {

    @Resource
    private SpecialCargoOogMapper specialCargoOogMapper;
    @Resource
    private SpecialCargoOdoMapper specialCargoOdoMapper;
    @Resource
    private SpecialCargoDgMapper specialCargoDgMapper;
    @Resource
    private SpecialCargoFlexiMapper specialCargoFlexiMapper;
    @Resource
    private CargoCntrTypeRelationMapper cargoCntrTypeRelationMapper;
    @Resource
    private SpecialCargoDgPackingMapper specialCargoDgPackingMapper;
    @Resource
    private SpecialCargoCasMapper specialCargoCasMapper;
    @Resource
    private ApplySaveOrUpdateService applySaveOrUpdateService;
    @Resource
    private SpecialCargoDgExtMapper specialCargoDgExtMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createOrUpdateOog(OogCreateOrUpdateVO createReqVO) {
        List<CntrAndOogBaseVO> cntrAndOogInfos = createReqVO.getCntrAndOogInfos();
        List<SpecialCargoCntrBaseVO> cntrList = cntrAndOogInfos.stream().map(CntrAndOogBaseVO::getCntrBaseInfo).collect(Collectors.toList());
        applySaveOrUpdateService.checkCntrSizeType(createReqVO.getSoId(), cntrList);
        SpecialCargoApplyDO applyDO = SpecialCargoApplyConvert.INSTANCE.convert(createReqVO);
        Long applyId = applySaveOrUpdateService.saveOrUpdateApply(applyDO);
        applySaveOrUpdateService.saveOrUpdateVoyage(createReqVO.getSpcVoyageInfo(), applyId, createReqVO.getPartnerFlag());
        List<Long> cntrIds = new ArrayList<>();
        cntrAndOogInfos.forEach(cntr -> {
            if (null != cntr && null != cntr.getCntrBaseInfo()) {
                Long cntrId = applySaveOrUpdateService.saveOrUpdateCntr(cntr.getCntrBaseInfo(), applyId);
                cntrIds.add(cntrId);
                if (null != cntr.getOogBaseInfo()) {
                    SpecialCargoOogDO oogDO = SpecialCargoOogConvert.INSTANCE.convert(cntr.getOogBaseInfo());
                    oogDO.setCntrId(cntrId);
                    if (null != cntr.getOogBaseInfo().getId()) {
                        specialCargoOogMapper.updateById(oogDO);
                    } else {
                        specialCargoOogMapper.insert(oogDO);
                    }
                }
            }
        });
        //删除多余像数据
        applySaveOrUpdateService.removeCntr(applyId, cntrIds);
        applySaveOrUpdateService.spcAttachmentSaveOrUpdate(createReqVO.getSpcAttachmentList(), applyId);
        return applyId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createOrUpdateOdo(OdoCreateOrUpdateVO createReqVO) {
        List<CntrAndOdoBaseVO> cntrAndOdoInfos = createReqVO.getCntrAndOdoInfos();
        List<SpecialCargoCntrBaseVO> cntrList = cntrAndOdoInfos.stream().map(CntrAndOdoBaseVO::getCntrBaseInfo).collect(Collectors.toList());
        applySaveOrUpdateService.checkCntrSizeType(createReqVO.getSoId(), cntrList);
        SpecialCargoApplyDO applyDO = SpecialCargoApplyConvert.INSTANCE.convert(createReqVO);
        Long applyId = applySaveOrUpdateService.saveOrUpdateApply(applyDO);
        applySaveOrUpdateService.saveOrUpdateVoyage(createReqVO.getSpcVoyageInfo(), applyId, createReqVO.getPartnerFlag());
        List<Long> cntrIds = new ArrayList<>();
        cntrAndOdoInfos.forEach(cntr -> {
            if (null != cntr && null != cntr.getCntrBaseInfo()) {
                Long cntrId = applySaveOrUpdateService.saveOrUpdateCntr(cntr.getCntrBaseInfo(), applyId);
                cntrIds.add(cntrId);
                if (null != cntr.getOdoBaseInfo()) {
                    SpecialCargoOdoDO odoDO = SpecialCargoOdoConvert.INSTANCE.convert(cntr.getOdoBaseInfo());
                    odoDO.setCntrId(cntrId);
                    if (null != cntr.getOdoBaseInfo().getId()) {
                        specialCargoOdoMapper.updateById(odoDO);
                    } else {
                        specialCargoOdoMapper.insert(odoDO);
                    }
                }
            }
        });
        applySaveOrUpdateService.removeCntr(applyId, cntrIds);
        applySaveOrUpdateService.spcAttachmentSaveOrUpdate(createReqVO.getSpcAttachmentList(), applyId);
        return applyId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createOrUpdateFlexi(FlexiCreateOrUpdateVO createReqVO) {
        List<CntrAndFlexiBaseVO> cntrAndFlexiInfos = createReqVO.getCntrAndFlexiInfos();
        List<SpecialCargoCntrBaseVO> cntrList = cntrAndFlexiInfos.stream().map(CntrAndFlexiBaseVO::getCntrBaseInfo).collect(Collectors.toList());
        applySaveOrUpdateService.checkCntrSizeType(createReqVO.getSoId(), cntrList);
        SpecialCargoApplyDO applyDO = SpecialCargoApplyConvert.INSTANCE.convert(createReqVO);
        Long applyId = applySaveOrUpdateService.saveOrUpdateApply(applyDO);
        applySaveOrUpdateService.saveOrUpdateVoyage(createReqVO.getSpcVoyageInfo(), applyId, createReqVO.getPartnerFlag());
        List<Long> cntrIds = new ArrayList<>();
        cntrAndFlexiInfos.forEach(cntr -> {
            if (null != cntr && null != cntr.getCntrBaseInfo()) {
                Long cntrId = applySaveOrUpdateService.saveOrUpdateCntr(cntr.getCntrBaseInfo(), applyId);
                cntrIds.add(cntrId);
                if (null != cntr.getFlexiBaseInfo()) {
                    SpecialCargoFlexiDO flexiDO = SpecialCargoFlexiConvert.INSTANCE.convert(cntr.getFlexiBaseInfo());
                    flexiDO.setCntrId(cntrId);
                    if (null != cntr.getFlexiBaseInfo().getId()) {
                        specialCargoFlexiMapper.updateById(flexiDO);
                    } else {
                        specialCargoFlexiMapper.insert(flexiDO);
                    }
                }
            }
        });
        applySaveOrUpdateService.removeCntr(applyId, cntrIds);
        applySaveOrUpdateService.spcAttachmentSaveOrUpdate(createReqVO.getSpcAttachmentList(), applyId);
        return applyId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createOrUpdateDg(DgCreateOrUpdateVO createReqVo) {
        CntrAndDgBaseVO cntrAndDgInfos = createReqVo.getCntrAndDgInfos();
        List<SpecialCargoCntrBaseVO> cntrList = cntrAndDgInfos.getCntrBaseInfo();
        applySaveOrUpdateService.checkCntrSizeType(createReqVo.getSoId(), cntrList);
        SpecialCargoApplyDO applyDo = SpecialCargoApplyConvert.INSTANCE.convert(createReqVo);
        applyDo.setTransitCnsha(applySaveOrUpdateService.updateTransitCnsha(createReqVo.getPolCode(), createReqVo.getPodCode(), createReqVo.getSpcVoyageInfo()));
        Long applyId = applySaveOrUpdateService.saveOrUpdateApply(applyDo);
        applySaveOrUpdateService.saveOrUpdateVoyage(createReqVo.getSpcVoyageInfo(), applyId, createReqVo.getPartnerFlag());
        //收集临时label对应的dgId
        Map<Long, Long> labelDgIdMap = new HashMap<>(16);
        //收集DG信息更新或保存
        List<Long> dgIds = new ArrayList<>();
        cntrAndDgInfos.getDgBaseInfo().forEach(dg -> {
            if (null != dg) {
                HashMap<String, String> dgExt = dg.getDgExt();
                SpecialCargoDgDO dgDO = SpecialCargoDgConvert.INSTANCE.convert(dg);
                dgDO.setApplyId(applyId);
                if (null != dg.getId()) {
                    specialCargoDgMapper.updateById(dgDO);
                } else {
                    specialCargoDgMapper.insert(dgDO);
                }
                if (dgExt != null && !dgExt.isEmpty()) {
                    for (String key : dgExt.keySet()) {
                        SpecialCargoDgExtDO dgExtDO = specialCargoDgExtMapper.selectOne(new LambdaQueryWrapperX<SpecialCargoDgExtDO>()
                                .eq(SpecialCargoDgExtDO::getDgId, dgDO.getId()).eqIfPresent(SpecialCargoDgExtDO::getExtName, key));
                        if (null != dgExtDO) {
                            dgExtDO.setExtValue(dgExt.get(key));
                            specialCargoDgExtMapper.updateById(dgExtDO);
                        } else {
                            dgExtDO = new SpecialCargoDgExtDO();
                            dgExtDO.setDgId(dgDO.getId());
                            dgExtDO.setExtName(key);
                            dgExtDO.setExtValue(dgExt.get(key));
                            specialCargoDgExtMapper.insert(dgExtDO);
                        }
                    }

                }
                dgIds.add(dgDO.getId());
                labelDgIdMap.put(dg.getDgLabel(), dgDO.getId());
                List<PackingCreateOrUpdateVO> innerDgPacking = dg.getInnerDgPacking();
                if (CollectionUtil.isNotEmpty(innerDgPacking)) {
                    innerDgPacking.forEach(dgPacking -> {
                        if (null != dgPacking) {
                            SpecialCargoDgPackingDO dgPackingDo = SpecialCargoDgPackingConvert.INSTANCE.convert(dgPacking);
                            dgPackingDo.setPackingType(PackingEnum.INNER.getValue());
                            dgPackingDo.setDgId(dgDO.getId());
                            if (null != dgPacking.getId()) {
                                specialCargoDgPackingMapper.updateById(dgPackingDo);
                            } else {
                                specialCargoDgPackingMapper.insert(dgPackingDo);
                            }
                        }
                    });
                }
                List<PackingCreateOrUpdateVO> outerDgPacking = dg.getOuterDgPacking();
                if (CollectionUtil.isNotEmpty(outerDgPacking)) {
                    outerDgPacking.forEach(dgPacking -> {
                        if (null != dgPacking) {
                            SpecialCargoDgPackingDO dgPackingDo = SpecialCargoDgPackingConvert.INSTANCE.convert(dgPacking);
                            dgPackingDo.setPackingType(PackingEnum.OUTER.getValue());
                            dgPackingDo.setDgId(dgDO.getId());
                            if (null != dgPacking.getId()) {
                                specialCargoDgPackingMapper.updateById(dgPackingDo);
                            } else {
                                specialCargoDgPackingMapper.insert(dgPackingDo);
                            }
                        }
                    });
                }
                List<CasCreateOrUpdateVO> dgCasInfo = dg.getDgCasInfo();
                if (CollectionUtil.isNotEmpty(dgCasInfo)) {
                    List<SpecialCargoCasDO> specialCargoCas = SpecialCargoCasConvert.INSTANCE.convertDoList(dgCasInfo);
                    List<SpecialCargoCasDO> nullIdList = specialCargoCas.stream().filter(cargo -> cargo.getId() == null)
                            .peek(cargo -> cargo.setSpecialCargoDgId(dgDO.getId())).collect(Collectors.toList());
                    List<SpecialCargoCasDO> withIdList = specialCargoCas.stream().filter(cargo -> cargo.getId() != null)
                            .peek(cargo -> cargo.setSpecialCargoDgId(dgDO.getId())).collect(Collectors.toList());
                    if (CollectionUtil.isNotEmpty(nullIdList)) {
                        specialCargoCasMapper.insertBatch(nullIdList);
                    }
                    if (CollectionUtil.isNotEmpty(withIdList)) {
                        specialCargoCasMapper.updateBatch(withIdList);
                    }
                }
            }
        });

        //收集箱子信息更新或保存，和箱子下挂的DG信息处理
        List<Long> cntrIds = new ArrayList<>();
        cntrAndDgInfos.getCntrBaseInfo().forEach(cntr -> {
            if (null != cntr) {
                Long cntrId = applySaveOrUpdateService.saveOrUpdateCntr(cntr, applyId);
                cntrIds.add(cntrId);
                List<Long> dgIdsByClient = new ArrayList<>();
                List<Long> dgLabels = cntr.getDgLabels();
                if (null != dgLabels) {
                    for (Long dgLabel : dgLabels) {
                        Long dgLab = labelDgIdMap.get(dgLabel);
                        if (null == dgLab) {
                            throw ServiceExceptionUtil.exception(SpecialCargoApplyErrorCodeConstants.SPECIAL_APPLY_DG_LABEL_ERROR);
                        }
                        dgIdsByClient.add(labelDgIdMap.get(dgLabel));
                    }
                }
                List<Long> dgIdsByTable = new ArrayList<>();
                List<CargoCntrTypeRelationDO> cntrDgRelations = cargoCntrTypeRelationMapper.selectList(new LambdaQueryWrapperX<CargoCntrTypeRelationDO>().eq(CargoCntrTypeRelationDO::getCntrId, cntrId));
                if (CollectionUtil.isNotEmpty(cntrDgRelations)) {
                    dgIdsByTable = cntrDgRelations.stream().map(CargoCntrTypeRelationDO::getDgId).collect(Collectors.toList());
                }
                List<Long>[] symmetricDifference = CommonUtil.getSymmetricDifference(dgIdsByClient, dgIdsByTable);
                List<Long> dgIdsClient = symmetricDifference[0];
                List<Long> dgIdsTable = symmetricDifference[1];
                //客户端传过来的关系表里没有维护的DG新增插入
                if (CollectionUtil.isNotEmpty(dgIdsClient)) {
                    List<CargoCntrTypeRelationDO> newDOList = CollectionUtil.newArrayList();
                    for (Long dgId : dgIdsClient) {
                        CargoCntrTypeRelationDO cntrDgRelation = new CargoCntrTypeRelationDO();
                        cntrDgRelation.setDgId(dgId);
                        cntrDgRelation.setApplyId(applyId);
                        cntrDgRelation.setCntrId(cntrId);
                        cntrDgRelation.setApplyType(SpecialEnum.DG.getValue());
                        newDOList.add(cntrDgRelation);
                    }
                    cargoCntrTypeRelationMapper.insertBatch(newDOList);
                }
                //客户端没传但是关系表里有的DG删除
                if (CollectionUtil.isNotEmpty(dgIdsTable)) {
                    List<Long> deleteIds = cntrDgRelations.stream().filter(relation -> dgIdsTable.contains(relation.getDgId()))
                            .map(CargoCntrTypeRelationDO::getId).collect(Collectors.toList());
                    cargoCntrTypeRelationMapper.deleteBatchIds(deleteIds);
                }
            }
        });
        applySaveOrUpdateService.removeCntr(applyId, cntrIds);
        applySaveOrUpdateService.removeDg(applyId, dgIds);
        applySaveOrUpdateService.spcAttachmentSaveOrUpdate(createReqVo.getSpcAttachmentList(), applyId);
        return applyId;
    }
}
